package uk.ac.strath.cis.religionsearch.model.indexer;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.ExtendedBaseRules;
import org.xml.sax.SAXException;

import org.apache.lucene.LucenePackage;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

public class Indexer{
    private static IndexWriter writer;
    private File[] files;
    private String outputPath;
    private ArrayList<Tstmt> tstmts;

    public void startIndexing() throws IOException{
    	Document contactDocument;
    	String bktlong;
    	String bktitle;
    	ArrayList<verseContainer> bookcoll;
    	System.out.print("Indexing Started...");
    	for(int x=0;x<tstmts.size();x++){
    		
    		Tstmt t = tstmts.get(x);
    		bktitle = t.getTitle();
    		bookcoll = t.getBooks();
    		
    	for(int i=0;i<bookcoll.size();i++){
    		if(bookcoll.get(i).hasChapters()){
    			Book currentBook = (Book) bookcoll.get(i);
    			ArrayList<Chapter> chapters = currentBook.getChapters();
    			bktlong = currentBook.getBktlong();
    		
    		for(int j=0;j<chapters.size();j++){
    			String s = chapters.get(j).getChtitle();
    			ArrayList<String> verses = chapters.get(j).getVerses();
    			
    			
    			for(int k=0;k<verses.size();k++){
    				contactDocument = new Document();
    	            contactDocument.add(new Field("verse", verses.get(k), Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("chtitle", chapters.get(j).getChtitle(), Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("bktlong", bktlong, Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("title", bktitle, Field.Store.YES, Field.Index.ANALYZED));
    	            writer.addDocument(contactDocument);
    			}
    		}
    			
    		} else {
    			Sura currentBook = (Sura) bookcoll.get(i);
    			bktlong = currentBook.getSuraTitle();
    		
    			ArrayList<String> verses = currentBook.getVerses();
    			
    			for(int k=0;k<verses.size();k++){
    				contactDocument = new Document();
    	            contactDocument.add(new Field("verse", verses.get(k), Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("chtitle", bktlong, Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("bktlong", bktlong, Field.Store.YES, Field.Index.ANALYZED));
    	            contactDocument.add(new Field("title", bktitle, Field.Store.YES, Field.Index.ANALYZED));
    	            writer.addDocument(contactDocument);
    			}

    		}
    	}
    	
    	System.out.println("Done!");
    	}
    }
    
    public void storeTstmtForIndexing(Tstmt t){
    	if(tstmts==null)
    		tstmts = new ArrayList<Tstmt>();
    	tstmts.add(t);
    }
    
    public void init(File[] children, String outputPath) throws IOException, SAXException{
    	System.out.println("Indexer initialised...");
    	this.files = children;
    	this.outputPath = outputPath;
		start();

    }
    
    public void start() throws IOException, SAXException {
    	
    	FSDirectory dir = FSDirectory.open(new File(outputPath));
    	Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
        boolean createFlag = true;
    	writer = new IndexWriter(dir, analyzer, createFlag, IndexWriter.MaxFieldLength.UNLIMITED);
    	
    for(int i=0;i<files.length;i++){                                         // THIS WILL OVERWRITE THE INDEX FOR EVERY FILE - FIX!
        
        System.out.println("Opening file " + files[i].getAbsolutePath());
        System.out.print("Parsing Started...");
        
        Digester digester = new Digester();
        digester.setValidating(false);
        
        /*        	digester.addObjectCreate("tstmt/", Tstmt.class );
        	digester.addBeanPropertySetter("tstmt/coverpg/title",       "title");
      
        		digester.addObjectCreate("tstmt/bookcoll/book", Book.class );
        		digester.addCallMethod("tstmt/bookcoll/book/bktlong",       "setBktlong", 0);
        
        			digester.addObjectCreate("tstmt/bookcoll/book/chapter", Chapter.class );
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/chtitle",    "setChtitle", 0);
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/v",       "setVerse", 0);
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/div/v",       "setVerse", 0);
        			digester.addSetNext("tstmt/bookcoll/book/chapter",               "addChapter" );

        		digester.addSetNext("tstmt/bookcoll/book", "addBook");  	
        		
        		digester.addObjectCreate("tstmt/bookcoll/sura", Sura.class );
        			
        		digester.addCallMethod("tstmt/bookcoll/sura/bktlong",       "setSuraTitle", 0);
        			digester.addCallMethod("tstmt/bookcoll/sura/v",       "setVerse", 0);
        			digester.addSetNext("tstmt/bookcoll/sura/bktshort",               "addChapter" );
        			
        		digester.addSetNext("tstmt/bookcoll/sura", "addBook"); 
        		
        		System.out.println("Done!");
*/
        
       

        	digester.addObjectCreate("tstmt/", Tstmt.class );
        	digester.addBeanPropertySetter("tstmt/coverpg/title",       "title");
      
        		digester.addObjectCreate("tstmt/bookcoll/book", Book.class );
        		digester.addCallMethod("tstmt/bookcoll/book/bktlong",       "setBktlong", 0);
        
        			digester.addObjectCreate("tstmt/bookcoll/book/chapter", Chapter.class );
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/chtitle",    "setChtitle", 0);
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/v",       "setVerse", 0);
        			digester.addCallMethod("tstmt/bookcoll/book/chapter/div/v",       "setVerse", 0);
        			digester.addSetNext("tstmt/bookcoll/book/chapter",               "addChapter" );

        		digester.addSetNext("tstmt/bookcoll/book", "addBook");  	
        		
        		System.out.println("Done!");

        storeTstmtForIndexing((Tstmt)digester.parse(files[i]));
        
        
      }
    	startIndexing();
    	writer.optimize();
        writer.close();
    }
    
    public static interface verseContainer{
    	public boolean hasChapters();

    }
    
    public static class Tstmt{
    	private String title; // The New Testament
    	private ArrayList<verseContainer> bookcoll;
    	
    	public ArrayList<verseContainer> getBooks(){
    		return bookcoll;
    	}
    	
    	public void addBook(Book b){
    		if (bookcoll==null)
    			bookcoll = new ArrayList<verseContainer>();
    		bookcoll.add(b);
    	}

		public String getTitle() {
			return title;
		}

		public void setTitle(String title) {
			this.title = title;
		}
    }
    
    public static class Book implements verseContainer{
    	private String bktlong; // E.g. The gospel according to saint mark
		private ArrayList<Chapter> chapters;
    	
    	public ArrayList<Chapter> getChapters(){
    		return chapters;
    	}
    	
    	public void addChapter(Chapter c){
    		if (chapters==null)
    			chapters = new ArrayList<Chapter>();
    		chapters.add(c);
    	}
    	
    	public String getBktlong() {
			return bktlong;
		}

		public void setBktlong(String bktlong) {
			this.bktlong = bktlong;
		}

		@Override
		public boolean hasChapters() {
			return true;
		}
    }
    
    public static class Sura implements verseContainer{
    	private String suraTitle;
    	private ArrayList<String> verses;
    	
    	
    	public String getSuraTitle(){
    		return suraTitle;
    	}
    	
    	public void setSuraTitle(String s){
    		suraTitle = s;
    	}
    	
    	public ArrayList<String> getVerses(){
			return verses;
		}
    	
		public void setVerse(String verse){
			if (verses==null)
				verses = new ArrayList<String>();
			verses.add(verse);
		}

		@Override
		public boolean hasChapters() {
			return false;	
		}
    }
    
    public static class Chapter{

        private String chtitle; // E.g. chapter 5
        private ArrayList<String> verses;

        public ArrayList<String> getVerses(){
			return verses;
		}
        
		public void setVerse(String verse){
			if (verses==null)
				verses = new ArrayList<String>();
			verses.add(verse);
		}
		
		public String getChtitle(){
			return chtitle;
		}
		
		public void setChtitle(String chtitle){
			this.chtitle = chtitle;
		}
    }
}
